<!--
 * @Author: huangtianyang 916072572@qq.com
 * @Date: 2023-11-16 10:31:41
 * @LastEditors: huangtianyang
 * @LastEditTime: 2024-05-14 09:47:59
 * @FilePath: \driving-training-admin\src\components\form\Index.vue
-->
<template>
    <div class="custom-form" ref="formElmentRef">
        <div class="block" v-for="item in formData" :key="item">
            <!-- 对象为 object -->
            <template v-if="Object.prototype.toString.call(item) === '[object Object]'">
                <h3 class="small-title">{{ item.title }}</h3>
            </template>
            <!-- 对象为 array -->
            <template v-if="Object.prototype.toString.call(item) === '[object Array]'">
                <div class="col" v-for="child in item" :key="child">
                    <div class="item-label">
                        <i v-if="child.required">*</i>
                        <p>{{ child.label }}</p>
                    </div>
                    <div class="item-content">
                        <!-- 编辑器 -->
                        <template v-if="child.type === 'tinymce'">
                            <div style="width: 100%" :key="child">
                                <TinymceVue
                                    :content="child.value"
                                    @update="
                                        (res: string) => {
                                            child.value = res
                                            child.valid = true
                                        }
                                    "
                                    v-if="!disabled"
                                />
                                <div v-else v-html="child.value" style="line-height: 32px"></div>
                            </div>
                        </template>
                        <template v-else>
                            <div :key="child">
                                <div>
                                    <!-- 类型 text number 输入框  文本域-->
                                    <template
                                        v-if="
                                            child.type === 'text' ||
                                            child.type === 'number' ||
                                            child.type === 'textarea'
                                        "
                                    >
                                        <div style="display: flex; align-items: center">
                                            <el-input
                                                :class="[child.valid ? '' : 'error']"
                                                v-model="child.value"
                                                :type="child.type"
                                                clearable
                                                :placeholder="child.message"
                                                :disabled="disabled ? disabled : child.disabled"
                                                :maxlength="child.maxlength ? child.maxlength : ''"
                                                show-word-limit
                                                style="width: 300px"
                                                @blur="
                                                    res => {
                                                        if (child.required && child.trigger === 'blur') {
                                                            child.valid = child.value ? true : false
                                                            if (!child.valid) {
                                                                child.message =
                                                                    child.placeholder + child.label.replace(/：/g, '')
                                                            }
                                                        }
                                                        if (child.rvalidateVent === 'phone' && child.value) {
                                                            child.valid = regMobile(child.value) ? true : false
                                                            if (!child.valid) {
                                                                child.message = child.rvalidateErrorMsg
                                                            }
                                                        }
                                                    }
                                                "
                                            ></el-input>
                                            <!-- 单位 -->
                                            <span style="margin-left: 4px">{{ child.unit }}</span>
                                        </div>
                                    </template>
                                    <!-- 下拉框 -->
                                    <template v-else-if="child.type === 'select'">
                                        <el-select
                                            :class="[child.valid ? '' : 'error']"
                                            v-model="child.value"
                                            style="width: 300px"
                                            :disabled="disabled"
                                            @change="
                                                (res: any) => {
                                                    if (child.required && child.trigger === 'change') {
                                                        console.log(child.value)
                                                        child.valid = child.value ? true : false
                                                    }
                                                }
                                            "
                                        >
                                            <template v-if="child.options.length">
                                                <el-option
                                                    v-for="itemOption in child.options"
                                                    :key="itemOption.value"
                                                    :label="itemOption.label"
                                                    :value="itemOption.value"
                                                />
                                            </template>
                                            <template v-else>
                                                <el-option
                                                    v-for="itemOption in DICT_DATA.get(child.key)"
                                                    :key="itemOption.value"
                                                    :label="itemOption.label"
                                                    :value="itemOption.value"
                                                />
                                            </template>
                                        </el-select>
                                    </template>
                                    <!-- 多选框 -->
                                    <template v-else-if="child.type === 'checkbox-group'">
                                        <el-checkbox-group
                                            v-model="child.value"
                                            @change="
                                                (res: any) => {
                                                    console.log(res, child.value)
                                                    child.valid = true
                                                }
                                            "
                                        >
                                            <template v-if="child.options.length">
                                                <el-checkbox
                                                    v-for="key in child.options"
                                                    :key="key"
                                                    :label="key.value"
                                                    :value="key.value"
                                                    >{{ key.label }}</el-checkbox
                                                >
                                            </template>
                                            <template v-else>
                                                <el-checkbox
                                                    v-for="key in DICT_DATA.get(child.key)"
                                                    :key="key.value"
                                                    :label="key.value"
                                                    :value="key.value"
                                                    >{{ key.label }}</el-checkbox
                                                >
                                            </template>
                                        </el-checkbox-group>
                                    </template>
                                    <!-- tag 标签 -->
                                    <template v-else-if="child.type === 'tag'">
                                        <tagVue
                                            :data="child.value"
                                            :disabled="disabled"
                                            @delete="
                                                (res: string) => {
                                                    child.value.splice(child.value.indexOf(res), 1)
                                                }
                                            "
                                            @add="
                                                (res: string) => {
                                                    child.value.push(res)
                                                    child.valid = true
                                                }
                                            "
                                        />
                                    </template>
                                    <!-- 上传图片/视频 -->
                                    <template v-else-if="child.type === 'file'">
                                        <div>
                                            <p class="hint">{{ child.hint }}</p>
                                            <div class="upload-box">
                                                <UploadFileGroupVue
                                                    :data="child"
                                                    :disabled="disabled"
                                                    @change="
                                                        (obj: any) => {
                                                            console.log('change', obj)
                                                            child.valid = true
                                                            child.value[obj.index] = obj.obj
                                                        }
                                                    "
                                                    @delete="
                                                        (res: any) => {
                                                            child.value[res.index] = {
                                                                index: res.index,
                                                                list: [],
                                                                tag: '',
                                                                type: 'image'
                                                            }
                                                            console.log('delete', res.index, child.value)
                                                        }
                                                    "
                                                ></UploadFileGroupVue>
                                            </div>
                                        </div>
                                    </template>
                                    <!-- 地区选择 -->
                                    <template v-else-if="child.type === 'addr'">
                                        <div style="width: 100%; height: 100%">
                                            <addressVue
                                                :value="child.value"
                                                v-model:detailed="child.detailed"
                                                :hasDetailed="child.hasDetailed"
                                                :region="child.region"
                                                :disabled="disabled"
                                                :class="[child.valid ? '' : 'error']"
                                                :latLng="child.latLng || []"
                                                style="width: 300px"
                                                @latLng="
                                                    (res: any) => {
                                                        console.log('latLng', res)
                                                        child.latLng[0] = res.lat
                                                        child.latLng[1] = res.lng
                                                        child.value[0] = res.province
                                                        child.value[1] = res.city
                                                    }
                                                "
                                                @change="
                                                    (res: any) => {
                                                        child.valid = res ? true : false
                                                        child.value = [...res]
                                                        console.log('child', res)
                                                    }
                                                "
                                            />
                                        </div>
                                    </template>
                                    <!-- 地区地址选择 -->
                                    <template v-else-if="child.type === 'map'">
                                        <div style="width: 300px">
                                            <MapSelete
                                                :value="child.value"
                                                :disabled="disabled"
                                                :class="[child.valid ? '' : 'error']"
                                                :latLng="child.latLng"
                                                @change="
                                                    (res: any) => {
                                                        child.valid = res ? true : false
                                                        child.value = res.address
                                                        child.latLng[0] = res.lat
                                                        child.latLng[1] = res.lng
                                                        child.regionId = res.adcode + ''

                                                        console.log('map', res)
                                                    }
                                                "
                                            />
                                        </div>
                                    </template>
                                    <!-- 标签列表带描述 -->
                                    <template v-else-if="child.type === 'labelList'">
                                        <labelVue
                                            :value="child.value"
                                            :sort="child.hasSort"
                                            :count="child.count"
                                            :disabled="disabled"
                                            @change="
                                                (res: string) => {
                                                    child.valid = true
                                                    child.value.length = 0
                                                    child.value.push(...res)
                                                }
                                            "
                                        ></labelVue>
                                    </template>
                                    <!-- 时间选择 -->
                                    <template v-else-if="child.type === 'time'">
                                        起：
                                        <el-time-select
                                            v-model="child.value[0]"
                                            :max-time="child.value[1]"
                                            class="mr-4"
                                            placeholder="开始时间"
                                            start="08:30"
                                            step="00:15"
                                            end="22:30"
                                            style="width: 130px; margin-right: 10px"
                                            :disabled="disabled"
                                        />
                                        止：
                                        <el-time-select
                                            v-model="child.value[1]"
                                            :min-time="child.value[0]"
                                            placeholder="结束时间"
                                            start="08:30"
                                            step="00:15"
                                            end="22:30"
                                            style="width: 130px"
                                            :disabled="disabled"
                                        />
                                    </template>
                                    <!-- 单选 -->
                                    <template v-else-if="child.type === 'radio'">
                                        <el-radio-group v-model="child.value">
                                            <el-radio
                                                :label="itemOption.value"
                                                v-for="itemOption in child.options"
                                                :key="itemOption"
                                                >{{ itemOption.label }}</el-radio
                                            >
                                        </el-radio-group>
                                    </template>
                                    <!-- 月份选择 -->
                                    <template v-else-if="child.type === 'month'">
                                        <p class="hint" v-html="child.hint"></p>

                                        <el-config-provider :locale="locale">
                                            <el-date-picker
                                                v-model="child.value"
                                                type="month"
                                                format="YYYY-MM"
                                                value-format="YYYY-MM"
                                                placeholder="请选择月份"
                                                @change="data.onMonthChange"
                                                :disabled="disabled"
                                            />
                                        </el-config-provider>
                                    </template>
                                    <!-- radio-button -->
                                    <template v-else-if="child.type === 'radio-button'">
                                        <div class="col">
                                            <el-radio-group
                                                v-model="child.value"
                                                size="large"
                                                @change="
                                                    (res: any) => {
                                                        child.value = res
                                                        child.index = child.radioList.findIndex(
                                                            (item: string) => item === res
                                                        )
                                                    }
                                                "
                                            >
                                                <el-radio-button
                                                    v-for="radioChild in child.radioList"
                                                    :key="radioChild"
                                                    :label="radioChild"
                                                />
                                            </el-radio-group>
                                        </div>
                                        <div
                                            class="col"
                                            v-if="
                                                child.describe &&
                                                Number(child.index) !== Number(child.radioHideDescribeIndex)
                                            "
                                        >
                                            <el-input
                                                :class="[child.valid ? '' : 'error']"
                                                v-model="child.describe[Number(child.index)]"
                                                :type="child.type"
                                                clearable
                                                :placeholder="child.message"
                                                :disabled="disabled ? disabled : child.disabled"
                                                @blur="
                                                    res => {
                                                        if (child.required && child.trigger === 'blur') {
                                                            //child.valid = child.value ? true : false
                                                        }
                                                    }
                                                "
                                            ></el-input>
                                        </div>
                                        <div style="width: 100%" :key="child">
                                            <TinymceVue
                                                :content="child.content[Number(child.index)] || ''"
                                                @update="
                                                    (res: string) => {
                                                        child.content[Number(child.index)] = res
                                                        //child.valid = true
                                                    }
                                                "
                                                v-if="!disabled"
                                            />
                                            <div
                                                v-else
                                                v-html="child.content[Number(child.index)]"
                                                style="line-height: 32px"
                                            ></div>
                                        </div>
                                    </template>
                                </div>
                            </div>
                        </template>

                        <!-- 错误提示 -->
                        <div class="error-text" v-if="!child.valid">{{ child.message }}</div>
                    </div>
                </div>
            </template>
        </div>
    </div>
</template>

<script setup lang="ts">
import { onUnmounted, reactive, watchEffect, ref } from 'vue'
import { ElInput } from 'element-plus'
import UploadFileGroupVue from './uploadFileGroup.vue'
import TinymceVue from '@/components/Tinymce.vue'
import addressVue from './address.vue'
import tagVue from './tag.vue'
import labelVue from './labelList.vue'
import MapSelete from './mapSelete.vue'
import zhCn from 'element-plus/es/locale/lang/zh-cn'
import { regMobile } from '@/utils'
import { codeToText } from 'element-china-area-data'
import { DICT_DATA } from '@/utils/dict-data'

//receive parmas values from parent component
const props = defineProps(['data', 'disabled'])
const formData: any[] = reactive([])
const formElmentRef = ref()
const locale = ref(zhCn)

watchEffect(() => {
    formData.length = 0
    formData.push(...props.data)
})

//check input is pass
const validateForm = (): boolean => {
    let pass = true
    props.data.forEach((item: any[]) => {
        if (Object.prototype.toString.call(item) === '[object Array]') {
            item.forEach((child: any) => {
                if (child.type === 'labelList') {
                    let tagPass = false
                    child.value.forEach((tag: any) => {
                        if (tag.label) {
                            tagPass = true
                        }
                    })
                    if (child.required && !tagPass) {
                        child.valid = false
                        pass = false
                    }
                } else {
                    if (child.required) {
                        if (Object.prototype.toString.call(child.value) === '[object String]' && !child.value) {
                            child.valid = false
                            pass = false
                        } else if (
                            Object.prototype.toString.call(child.value) === '[object Array]' &&
                            !child.value.length
                        ) {
                            child.valid = false
                            pass = false
                        }
                        if (Object.prototype.toString.call(child.value) === '[object String]' && child.value) {
                            if (child.rvalidateVent === 'phone' && !regMobile(child.value)) {
                                console.log('phone error')
                                child.valid = false
                                pass = false
                            }
                        }
                    } else {
                        if (Object.prototype.toString.call(child.value) === '[object String]' && child.value) {
                            console.log('phone', child.value)
                            if (child.rvalidateVent === 'phone' && !regMobile(child.value)) {
                                console.log('phone error')
                                child.valid = false
                                pass = false
                                child.message = child.rvalidateErrorMsg
                            }
                        }
                    }
                }
            })
        }
    })
    if (!pass) {
        const box = document.querySelector('.information')
        box?.scrollTo({
            top: formElmentRef.value.offsetTop - 30,
            behavior: 'smooth'
        })
        console.log(pass)
    }

    return pass
}

//hide page and exit page reset data. 隐藏页面、退出页面重置数据
onUnmounted(() => {
    props.data.forEach((item: any[]) => {
        if (Object.prototype.toString.call(item) === '[object Array]') {
            item.forEach((child: any) => {
                if (Object.prototype.toString.call(child.value) === '[object String]') {
                    child.value = ''
                } else if (Object.prototype.toString.call(child.value) === '[object Array]') {
                    child.value.length = 0
                }
                if ('latLng' in child) {
                    child.latLng.length = 0
                }
                if ('describe' in child) {
                    child.describe.length = 0
                }
                if ('content' in child) {
                    child.content.length = 0
                }
            })
        }
    })
})

//outward exposure method 向外暴露方法
defineExpose({ validateForm, el: formElmentRef })
</script>

<style>
.small-title {
    font-size: 14px;
    margin-bottom: 12px;
    width: 170px;
    text-align: right;
    font-weight: bold;
}

.error .el-input__wrapper {
    /* box-shadow: 0 0 0 1px var(--color-error, var(--color-error)) inset !important; */
}
.el-select.error .el-input__wrapper.is-focus {
    /* box-shadow: 0 0 0 1px var(--color-error, var(--color-error)) inset !important; */
}

.upload-box {
    display: flex;
    flex-wrap: wrap;
}

.item-label {
    display: flex;
    align-items: center;
    width: 180px;
    justify-content: flex-end;
    padding-right: 8px;
    height: 32px;
    flex: 1;
}
.item-label i {
    color: var(--color-error);
    margin-right: 6px;
}
.block {
    display: flex;
    flex-wrap: wrap;
    width: 100%;
}
.col {
    display: flex;
    margin: 0 0 20px 0;
    min-width: 300px;
    box-sizing: border-box;
    padding-right: 16px;
    width: 100%;
}

.item-content {
    width: calc(100% - 180px);
    position: relative;
}
.error-text {
    position: absolute;
    bottom: -16px;
    left: 0;
    font-size: 12px;
    color: var(--color-error);
}
.hint {
    line-height: 32px;
}
</style>
./uploadFile.vue
